package org.nanhill.support.hibernate.search;

import java.util.LinkedList;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.nanhill.commons.lang.StringConstants;
import org.nanhill.commons.lang.StringKit;
import org.nanhill.support.hibernate.HibernateKit;

public abstract class HqlSearchVisitor extends HibernateSearchVisitor {
	private Query query;

	private StringBuilder hqlBuffer;

	/**
	 * The list of criteria to be used to constrain the search. This list may
	 * include parameter place holder characters that need to be populated.
	 */
	private List<String> criterias = new LinkedList<String>();

	/**
	 * The list of parameters for the search. Each parameter corresponds to a
	 * parameter place holder in the criteria list.
	 */
	private List<Object> parameters = new LinkedList<Object>();

	public HqlSearchVisitor() {
		super();
	}

	public HqlSearchVisitor(Session session) {
		super(session);
	}

	/**
	 * build the HQL query.
	 * 
	 */
	public void buildQuery() {
		hqlBuffer = new StringBuilder();
		buildSelect();
		buildFrom();
		buildWhere();
		buildLimit();
		buildHqlQuery();
	}

	/**
	 * Build the HQL FROM segment.
	 */
	protected abstract void buildFrom();

	/**
	 * Build the HQL SELECT segment.
	 */
	protected abstract void buildSelect();

	/**
	 * 
	 */
	protected abstract void buildLimit();

	/**
	 * Build the HQL WHERE segment.
	 * 
	 */
	protected void buildWhere() {
		if (criterias.size() > 0) {
			hqlBuffer.append("WHERE ");
			StringKit.buildIterator(hqlBuffer, criterias.iterator(), " AND",
					StringConstants.BLANK);
		}
	}

	/**
	 * Build Hibernate Query with HQL.
	 */
	private void buildHqlQuery() {
		query = getSession().createQuery(hqlBuffer.toString());
		HibernateKit.initQuery(query, parameters.iterator());
	}

	/**
	 * Adds a specific criterion with a given value if it does not already
	 * appear.
	 * 
	 * @param criterion
	 *            The column to be constrained.
	 * @param parameter
	 *            The value for the column.
	 */
	protected void addCriterion(String criterion, Object parameter) {
		criterias.add(criterion);
		parameters.add(parameter);
	}

	protected void append(String segment) {
		hqlBuffer.append(segment);
	}

	protected Query getQuery() {
		return query;
	}

}
